﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace Tools
{
    /// <summary>
    /// 字典辅助类,该类不负责线程同步
    /// </summary>
    public static class DictionaryUtil
	{
        /// <summary>
        /// Does a deep copy of a dictionary, optimizing for value types.  If 
        /// the key or value is not a value type (excluding strings), this method
        /// relies on the type's serialization capabilities.  If the type is not
        /// serializable, this method will fail.
        /// </summary>
		/// <typeparam name="K"></typeparam>
		/// <typeparam name="V"></typeparam>
		/// <param name="dict"></param>
		/// <returns></returns>
        public static IDictionary<K, V> CloneIDictionary<K, V>(IDictionary<K, V> dict)
		{
            Dictionary<K, V> newDict = null;

			// The clone method is immune to the source dictionary being null.
			if (dict != null)
			{
                newDict = new Dictionary<K, V>();
                /*// Clone by copying the value types.
                foreach (KeyValuePair<K, V> kvp in dict)
                {
                    newDict[kvp.Key] = kvp.Value;
                }

                return newDict;
                */
				// If the key and value are value types, clone without serialization.
				if (((typeof(K).IsValueType || typeof(K) == typeof(string)) &&
				    (typeof(V).IsValueType) || typeof(V) == typeof(string)))
				{
				    newDict = new Dictionary<K, V>();
				    // Clone by copying the value types.
				    foreach (KeyValuePair<K, V> kvp in dict)
				    {
				        newDict[kvp.Key] = kvp.Value;
				    }

                    //return newDict;
				}
				else
				{
					// Clone by serializing to a memory stream, then deserializing.
					// Don't use this method if you've got a large objects, as the
					// BinaryFormatter produces bloat, bloat, and more bloat.
					BinaryFormatter bf = new BinaryFormatter();
					MemoryStream ms = new MemoryStream();
					bf.Serialize(ms, dict);
					ms.Position = 0;
					newDict = (Dictionary<K, V>)bf.Deserialize(ms);
				}
                 
			}

			return newDict;
		}

        /// <summary>
        /// 复制字典，返回字典对象
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="V"></typeparam>
        /// <param name="dict"></param>
        /// <returns></returns>
        public static Dictionary<K, V> CloneDictionary<K, V>(IDictionary<K, V> dict)
        {
            IDictionary<K, V> idict = CloneIDictionary<K, V>(dict);

            return new Dictionary<K, V>(idict);
        }

        /// <summary>
        /// 循环字典
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="V"></typeparam>
        /// <param name="dict"></param>
        /// <param name="action"></param>
        public static void DictionaryEach<K, V>(IDictionary<K, V> dict, Action<KeyValuePair<K, V>> action)
        {
            DictionaryEach<K, V>(dict, null, action);
        }

        /// <summary>
        /// 循环字典，满足条件才做Action
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="V"></typeparam>
        /// <param name="dict"></param>
        /// <param name="predicate"></param>
        /// <param name="action"></param>
        public static void DictionaryEach<K, V>(IDictionary<K, V> dict, Predicate<KeyValuePair<K, V>> predicate, Action<KeyValuePair<K, V>> action)
        {
            if (dict == null || dict.Count == 0)
                return;

            //lock (dict)
            //{
                foreach (KeyValuePair<K, V> kvp in dict)
                {
                    if (predicate != null)
                    {
                        if (predicate(kvp))
                            action(kvp);
                    }
                    else
                        action(kvp);
                }
            //}
        }

        /// <summary>
        /// 根据Key循环字典里的所有的值，改值可在循环时修改
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="V"></typeparam>
        /// <param name="dict"></param>
        /// <param name="action"></param>
        public static void ValueEach<K, V>(IDictionary<K, V> dict, Action<V> action)
        {
            //lock (dict)
            //{
                K[] arr = new K[dict.Keys.Count];
                dict.Keys.CopyTo(arr, 0);
                for (int i = 0; i < arr.Length; i++)
                {
                    action(dict[arr[i]]);
                }
            //}
        }

        /// <summary>
        /// 返回在字典的值里第一个满足条件的值
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="V"></typeparam>
        /// <param name="dict"></param>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public static V FindOneValueByValue<K, V>(IDictionary<K, V> dict, Predicate<V> predicate)
        {
            KeyValuePair<K, V>? rtn = FindOneKeyValueByValue<K, V>(dict, predicate);
            if (rtn.HasValue)
            {
                return rtn.Value.Value;
            }

            return default(V);
        }

        /// <summary>
        /// 返回字典里满足值条件的第一个key-value对
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="V"></typeparam>
        /// <param name="dict"></param>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public static KeyValuePair<K, V>? FindOneKeyValueByValue<K, V>(IDictionary<K, V> dict, Predicate<V> predicate)
        {
            int count = dict.Keys.Count;
            if (count == 0)
                return null;

            KeyValuePair<K, V> rtn = new KeyValuePair<K,V>();
            bool isFound = false;

            //lock (dict)
            //{
                K[] arr = new K[count];
                dict.Keys.CopyTo(arr, 0);
                for (int i = 0; i < count; i++)
                {
                    if (predicate(dict[arr[i]]))
                    {
                        rtn = new KeyValuePair<K, V>(arr[i], dict[arr[i]]);
                        isFound = true;
                    }
                }
            //}
            if (isFound)
                return rtn;
            else
                return null;
        }

        /// <summary>
        /// 返回在字典的值里所有满足条件的值
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="V"></typeparam>
        /// <param name="dict"></param>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public static List<V> FindValuesByValue<K, V>(IDictionary<K, V> dict, Predicate<V> predicate)
        {
            List<V> list = new List<V>();

            DictionaryEach<K, V>(dict, delegate(KeyValuePair<K, V> kvp) {

                if (predicate(kvp.Value))
                    list.Add(kvp.Value);

            });

            return list;
        }

        /// <summary>
        /// 得到在字典里的值所有满足条件的Key的列表
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="V"></typeparam>
        /// <param name="dict"></param>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public static List<K> GetKeyListByValue<K, V>(IDictionary<K, V> dict, Predicate<V> predicate)
        {
            List<K> list = new List<K>();

            DictionaryEach<K, V>(dict, delegate(KeyValuePair<K, V> kvp)
            {

                if (predicate(kvp.Value))
                    list.Add(kvp.Key);

            });

            return list;
        }


        /// <summary>
        /// 两个字典进行拼接，如果目标字典包含了重复的Key，则保留原来的Key-Value
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="V"></typeparam>
        /// <param name="dict"></param>
        /// <param name="dictToJoin"></param>
        public static void Join<K, V>(IDictionary<K, V> dict, IDictionary<K, V> dictToJoin)
        {
            DictionaryEach<K, V>(dictToJoin, delegate(KeyValuePair<K,V> kvp) {
                /*
                if (dict.ContainsKey(kvp.Key))
                    return;
                else
                    dict.Add(kvp.Key, kvp.Value);
                */
                CheckContains(dict, kvp.Key, null, delegate(K key) { dict.Add(key, kvp.Value); });
            });
        }

        /// <summary>
        /// 检查字典里是否含有某个Key，如果含有，则执行actionTrue，否则执行actionFalse
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="V"></typeparam>
        /// <param name="dict"></param>
        /// <param name="key"></param>
        /// <param name="actionTrue"></param>
        /// <param name="actionFalse"></param>
        public static void CheckContains<K, V>(IDictionary<K, V> dict, K key, Action<K> actionTrue, Action<K> actionFalse)
        {
            if (dict.ContainsKey(key))
            {
                if (actionTrue != null)
                    actionTrue(key);
            }
            else
            {
                if (actionFalse != null)
                    actionFalse(key);
            }
        }
    }
}
